package com.luxf.base.domainevent.rocketmq;

import com.luxf.base.domainevent.eventtype.EventTypeLoader;
import com.luxf.base.domainevent.rocketmq.configuration.RocketMessageListenerMetadata;
import com.luxf.base.domainevent.rocketmq.utils.TopicUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.event.EventListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
public class RocketDomainEventNoticeListenerBeanRegister implements BeanPostProcessor, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Resource
    private RocketMessageListenerMetadata rocketMessageListenerMetadata;

    @Resource
    private EventTypeLoader eventTypeLoader;

    @Value(value = "${spring.application.name:default}")
    private String consumerGroupPrefix;

    private final Set<String> registeredTopic = new HashSet<>();

    @Nullable
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 获取标记了EventListener注解的方法
        List<Method> methods = new ArrayList<>();
        ReflectionUtils.doWithMethods(bean.getClass(), methods::add, method -> method.isAnnotationPresent(EventListener.class));
        if (CollectionUtils.isEmpty(methods)) {
            return bean;
        }
        for (Method method : methods) {
            // TODO: 此处获取第一个方法的参数. 按需改动
            Parameter oneParameter = method.getParameters()[0];
            String topic = TopicUtils.uniqueTopic(eventTypeLoader.loadClassTypeName(oneParameter.getType()));
            if (registeredTopic.contains(topic)) {
                continue;
            }
            // 默认应用名作为消费组前缀
            String consumerGroup = generateConsumerGroup(topic);
            RocketDomainEventNoticeListener<?> rocketDomainEventNoticeListener =
                    RocketDomainEventNoticeListener.create(
                            RocketMessageListenerProperties.create(rocketMessageListenerMetadata, topic,
                                    consumerGroup));
            String name = generateConsumerBeanName(RocketDomainEventNoticeListener.class.getSimpleName(),
                    topic);
            registerBean(name, rocketDomainEventNoticeListener);
            registeredTopic.add(topic);
            log.info("注册领域通知监听器{}", name);
        }
        return bean;
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private void registerBean(String beanName, RocketDomainEventNoticeListener<?> rocketMQListener) {
        ((GenericApplicationContext) this.applicationContext).registerBean(beanName,
                RocketDomainEventNoticeListener.class, () -> rocketMQListener);
    }

    private String generateConsumerGroup(String topic) {
        return consumerGroupPrefix + "%" + topic;
    }

    private String generateConsumerBeanName(String simpleName, String topic) {
        return String.format("%s_%s", simpleName, topic);
    }
}
